package sheep.view.Component;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.TextLayout;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.RoundRectangle2D;

import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.jdesktop.fuse.InjectedResource;
import org.jdesktop.fuse.ResourceInjector;

public class UserSelector extends JPanel {
    private final UserDetails userDetails;
    private final UserList userList;
    private final DefaultListModel userListModel;
    private final BorderPanel borderListPanel;
    private float shadowOffsetX;
    private float shadowOffsetY;
    private final JLabel jLabel;
    ////////////////////////////////////////////////////////////////////////////
    // THEME SPECIFIC FIELDS
    ////////////////////////////////////////////////////////////////////////////
    @InjectedResource
    private Color selectionColor, listColor, listItemColor;
    @InjectedResource
    private float selectionOpacity, selectionBorderOpacity, listOpacity,
                  listBorderOpacity, listUnselectedItemOpacity;
    @InjectedResource
    private Font listItemFont, listSelectedItemFont;
    @InjectedResource(key="Common.shadowColor")
    private Color shadowColor;
    @InjectedResource(key="Common.shadowOpacity")
    private float shadowOpacity;
    @InjectedResource
    private int shadowDistance;
    @InjectedResource(key="Common.shadowDirection")
    private int shadowDirection;

    public UserSelector() {
        super(new BorderLayout(0, 0));
        setOpaque(false);
        ResourceInjector.get().inject(this);
        computeShadow();
        userListModel = new DefaultListModel();
        userList = new UserList(userListModel);
        userDetails = new UserDetails();
        BorderLayout bdrlyt = new BorderLayout();
        borderListPanel = new BorderPanel();
        borderListPanel.setLayout(bdrlyt);
        borderListPanel.setOpaque(false);
        jLabel = new JLabel();
        jLabel.setText("FILTRES :");
        jLabel.setFont(listSelectedItemFont);
        jLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
        jLabel.setForeground(Color.WHITE);
        jLabel.setHorizontalAlignment(JLabel.CENTER);
        borderListPanel.add(jLabel,BorderLayout.NORTH );
        borderListPanel.add(userList, BorderLayout.CENTER);
        add(BorderLayout.CENTER, userDetails);
        add(BorderLayout.EAST, borderListPanel);
    }

    private void computeShadow() {
        double rads = Math.toRadians(shadowDirection);
        shadowOffsetX = (float) Math.cos(rads) * shadowDistance;
        shadowOffsetY = (float) Math.sin(rads) * shadowDistance;
    }

    public void addCat( String name) {
        if (userListModel.size() >= 9) {
            return;
        }
        userListModel.addElement( name );
    }

    public class BorderPanel extends JPanel{
              @Override
        public Dimension getPreferredSize() {
            Dimension parentSize = super.getPreferredSize();
            Dimension containerSize = UserSelector.this.getSize();
            return new Dimension(containerSize.width / 4,
                                 parentSize.height /2 - 10);
        }

        @Override
        // Dessine juste un bord arrondi
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
            Composite composite = g2.getComposite();
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       listOpacity));
            g2.setColor(listColor);
            RoundRectangle2D background;
            background = new RoundRectangle2D.Double(3.0, 3.0,
                                                     (double) getWidth() - 18.0,
                                                     (double) getHeight()/3 - 6.0,
                                                     10, 10);
            g2.fill(background);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       listBorderOpacity));
            Stroke stroke = g2.getStroke();
            g2.setStroke(new BasicStroke(3.0f));
            g2.draw(background);
            g2.setStroke(stroke);
            g2.setComposite(composite);
            super.paintComponent(g);
        }
      
    }
    public class UserList extends JList {
        private UserList(ListModel model) {
            super(model);
            setOpaque(false);
            setFont(listItemFont);
            setCellRenderer(new UsersListCellRenderer());
            addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
                    Rectangle bounds = getCellBounds(e.getFirstIndex(),e.getLastIndex());
                    if (bounds == null) 
                        return;
                    userDetails.repaint(userDetails.getWidth() - 20,bounds.y - 6,
                                        20,bounds.height + 12);
                }});
        }

    }

    // Element de la liste de droite
    private class UsersListCellRenderer extends DefaultListCellRenderer {
        private boolean isSelected;
        private int index;

        private UsersListCellRenderer() {
            super();
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = super.getPreferredSize();
            size.height = size.height+10;
            return size;
        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                                                      int index, boolean isSelected,
                                                      boolean cellHasFocus) {
            this.index = index;
            this.isSelected = isSelected;
            super.getListCellRendererComponent(list,(String)value,index, isSelected,
                                               cellHasFocus);
            setOpaque(false);
            setForeground(listItemColor);
            // Bordure différentes pour le premier et derier
            setBorder(BorderFactory.createEmptyBorder(index == 0 ? 19 : 5, 10, 
                    index == userListModel.size() - 1 ? 19 : 5, 10));
            // On change la police si selcetionné
            if (isSelected) {
                setFont(listSelectedItemFont);
            }
            return this;
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
            // Dessine la bordure blance d'un elem select
            if (isSelected) {
                paintSelection(g2);
            }
            // Ecrit le text
            paintText(g2);
        }

        // Dessine le bord d'un elem selectionné
        private void paintSelection(Graphics2D g2) {
            Composite composite = g2.getComposite();
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       selectionOpacity));
            g2.setColor(selectionColor);
            RoundRectangle2D background;
            double y = 2.0;
            double height = (double) getHeight() - 6.0;
            if (index == 0 || index == userListModel.size() - 1) 
                height -= 14;
            if (index == 0) 
                y += 14.0;
            background = new RoundRectangle2D.Double(-6.0, y,
                                                     (double) getWidth() + 3.0,
                                                     height,
                                                     12, 12);
            g2.fill(background);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       selectionBorderOpacity));
            Stroke stroke = g2.getStroke();
            g2.setStroke(new BasicStroke(3.0f));
            g2.draw(background);
            g2.setStroke(stroke);
            g2.setComposite(composite);
        }

        private Point paintText(Graphics2D g2) {
            FontMetrics fm = getFontMetrics(getFont());
            int x = getInsets().left;
            int y = getInsets().top + fm.getAscent();
            Composite composite = g2.getComposite();

            if (isSelected) {
                y -= 2;
                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                           shadowOpacity));
            } else {
                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                           listUnselectedItemOpacity));
            }
            g2.setColor(shadowColor);
            TextLayout layout = new TextLayout(getText(),getFont(),g2.getFontRenderContext());
            layout.draw(g2, x + (int) Math.ceil(shadowOffsetX), y + (int) Math.ceil(shadowOffsetY));
            if (isSelected) 
                g2.setComposite(composite);
            g2.setColor(getForeground());
            layout.draw(g2, x, y);
            if (!isSelected) 
                g2.setComposite(composite);
            return new Point(x, y + fm.getDescent());
        }
    }

    // Panneau de gauche
    public class UserDetails extends JPanel {  
        private UserDetails() {
            setOpaque(false);
        }
        
        @Override
        // Deesine le bord rond avec le lien à la liste
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            Composite composite = g2.getComposite();
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       selectionOpacity));
            g2.setColor(selectionColor);
            RoundRectangle2D background;
            background = new RoundRectangle2D.Double(3.0, 3.0,
                                                     (double) getWidth() - 10.0 - 3.0,
                                                     (double) getHeight() + (float)jLabel.getHeight() - 6.0,
                                                     12, 12);
            Area area = new Area(background);
            area.add(new Area(getSelectedRectangle()));
            g2.fill(area);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                                                       selectionBorderOpacity));
            Stroke stroke = g2.getStroke();
            g2.setStroke(new BasicStroke(3.0f));
            g2.draw(area);
            g2.setStroke(stroke);
            g2.setComposite(composite);
        }
        
        // Pour lier la liste au panel
        private Shape getSelectedRectangle() {
            int selectedIndex = userList.getSelectedIndex();
            Rectangle bounds = userList.getCellBounds(selectedIndex, selectedIndex);
            if (bounds == null)
                return new RoundRectangle2D.Double(0.0, 0.0, 0.0, 0.0, 1.0, 1.0);
            float x = getWidth() - 10.0f;
            float y = 2.0f + bounds.y + (float)jLabel.getHeight();
            float height = bounds.height - 6.0f;
            if (selectedIndex == 0 || selectedIndex == userListModel.size() - 1)
                height -= 14.0f;
            if (selectedIndex == 0) 
                y += 14.0f;
            GeneralPath gp = new GeneralPath();
            gp.moveTo(x - 5.0f, y- 6.0f);
            gp.lineTo(x, y - 6.0f);
            gp.quadTo(x, y, x + 6.0f, y);
            gp.lineTo(x + 20.0f, y);
            gp.lineTo(x + 20.0f, y + height);
            gp.lineTo(x + 6.0f, y + height);
            gp.quadTo(x, y + height, x, y + height + 6.0f);
            gp.lineTo(x - 5.0f, y + height + 6.0f);
            return gp;
        }
    }
}
